#!/usr/bin/env python
# _*_ coding:utf-8 _*_

# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of
# the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#     http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF
# ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR
# FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-11-03

""" the views of home module"""

import os
import json
import shutil
import random
import string

from io import BytesIO
from functools import wraps
from flask import render_template, url_for, redirect, flash, session,\
    request, make_response, abort
from PIL import Image, ImageFont, ImageDraw
from sqlalchemy import func
from flask_paginate import get_page_parameter, Pagination
from werkzeug.security import generate_password_hash


from app import db
from app.home.forms import LoginForm, RegistUser, PasswordForm
from app.models import Manufacturer, Hardware, User, TestReview, TestLog
from . import home


dir_server = os.path.dirname(os.path.realpath(__file__))
dir_results = os.path.abspath(os.path.join(dir_server, "../../results"))


def rnd_color():
    """随机颜色"""
    return (
        random.randint(32, 127), random.randint(32, 127),
        random.randint(32, 127))


def gene_text():
    """生成4位验证码"""
    return ''.join(random.sample(string.ascii_letters + string.digits, 4))


def draw_lines(draw, num, width, height):
    """划线"""
    for num in range(num):
        x1_coordinate = random.randint(0, width / 2)
        y1_coordinate = random.randint(0, height / 2)
        x2_coordinate = random.randint(0, width)
        y2_coordinate = random.randint(height / 2, height)
        draw.line(((x1_coordinate, y1_coordinate),
                   (x2_coordinate, y2_coordinate)), fill='black', width=1)


def get_verify_code():
    """生成验证码图形"""
    code = gene_text()
    # 图片大小120×50
    width, height = 120, 50
    # 新图片对象
    image = Image.new('RGB', (width, height), 'white')
    # 字体
    font = ImageFont.truetype('app/static/fonts/ubuntu.ttf', 40)
    # draw对象
    draw = ImageDraw.Draw(image)
    # 绘制字符串
    for item in range(4):
        draw.text(
            (5 + random.randint(-3, 3) + 23 * item, 5 + random.randint(-3, 3)),
            text=code[item], fill=rnd_color(), font=font)
    return image, code


@home.route('/code')
def get_code():
    """生产验证码"""
    image, code = get_verify_code()
    # 图片以二进制形式写入
    buf = BytesIO()
    image.save(buf, 'jpeg')
    buf_str = buf.getvalue()
    # 把buf_str作为response返回前端，并设置首部字段
    response = make_response(buf_str)
    response.headers['Content-Type'] = 'image/gif'
    # 将验证码字符串储存在session中
    session['image'] = code
    return response


def login_required(func_name):
    """登录验证装饰器"""
    @wraps(func_name)
    def decorated_function(*args, **kwargs):
        # if "user" not in session:  # 验证session
        if session.get('user'):
            return func_name(*args, **kwargs)
        return redirect(url_for('home.login', next=request.path))
    return decorated_function


@home.route("/hardware/del/<string:hardware_id>/<string:taskid>"
            "/<string:job_name>/", methods=["GET"])
@login_required
def job_del(hardware_id=None, taskid=None, job_name=None):
    """
    删除job日志
    """
    hardware_name = Hardware.query.filter_by(id=hardware_id).first().hardware
    job = TestLog.query.filter_by(job_name=job_name).filter_by(
        hardware_id=hardware_id).first()
    reviews = TestReview.query.filter_by(job_id=job.id).count()
    if reviews:
        return "<script>alert('该日志已被评审，不能被删除！');history.go(-1);</script>"
    db.session.delete(job)  # 删除数据
    db.session.commit()  # 提交数据
    menu_id = session.get('manu_id')
    namu_name = Manufacturer.query.filter_by(
        id=menu_id).first().manufacturer_name
    path = os.path.join(dir_results, namu_name, hardware_name, taskid,
                        job_name)
    tar_path = path + ".tar.gz"
    shutil.rmtree(path)
    os.remove(tar_path)
    return redirect(url_for('home.get_job', hardware_name=hardware_name,
                            task_id=taskid))


@home.route('/')
@login_required
def get_hardware():
    """获取硬件设备列表"""
    user_id = session.get("user_id")
    manu_name = User.query.filter_by(id=user_id).first().manufacturer
    manu_id = Manufacturer.query.filter_by(
        manufacturer_name=manu_name).first().id
    page = request.args.get('page', 1, type=int)  # 获取page参数值
    page_data = Hardware.query.filter_by(manu_id=manu_id).order_by(
        Hardware.id.desc()).paginate(page=page, per_page=10)
    return render_template('home/hardware_lst.html', page_data=page_data)


@home.route('/hardware/<string:hardware_name>', methods=['GET', 'POST'])
@login_required
def get_taskid(hardware_name=None):
    """获取硬件设备下所有task"""
    page = request.args.get('page', 1, type=int)  # 获取page参数值
    hardware_id = Hardware.query.filter_by(hardware=hardware_name).first().id
    page_data = TestLog.query.filter_by(hardware_id=hardware_id).paginate(
        page=page, per_page=10)
    return render_template("home/task_lst.html", hardware_name=hardware_name,
                           page_data=page_data)


@home.route('/hardware/<string:hardware_name>/<string:task_id>',
            methods=['GET', 'POST'])
@login_required
def get_job(hardware_name=None, task_id=None):
    """获取日志列表"""
    # results = []
    page = request.args.get('page', 1, type=int)  # 获取page参数值
    hardware = Hardware.query.filter_by(hardware=hardware_name).first()
    hardware_id = hardware.id
    menu_id = hardware.manu_id
    manu_name = Manufacturer.query.filter_by(
        id=menu_id).first().manufacturer_name
    page_data = TestLog.query.filter_by(hardware_id=hardware_id).filter_by(
        task_id=task_id).order_by(
        TestLog.id.desc()).paginate(page=page, per_page=10)
    return render_template("home/job_log.html", hardware_name=hardware_name,
                           task_id=task_id, manu_name=manu_name,
                           page_data=page_data)


@home.route('/results/<manu>/<host>/<task>/<job>/logs/<name>')
@login_required
def get_log(manu, host, task, job, name):
    """
    获取用例日志
    :param host:
    :param oec_id:
    :param job:
    :param name:
    :return:
    """
    dir_job = os.path.join(dir_results, manu, host, task, job)
    log_path = os.path.join(dir_job, name + '.log')
    if not os.path.exists(log_path):
        log_path = os.path.join(dir_job, 'job.log')
    try:
        with open(log_path, 'r') as log_file:
            log = log_file.read().split('\n')
    except OSError:
        abort(404)
    return render_template('home/log.html', name=name, log=log)


@home.route('/hardware/<string:manu>/<string:hardware>/'
            '<string:task_id>/<string:job_name>')
@login_required
def get_job_detail(manu=None, hardware=None, task_id=None, job_name=None):
    """
    获取job日志信息
    """
    dir_job = os.path.join(dir_results, manu, hardware, task_id, job_name)
    json_info = os.path.join(dir_job, 'compatibility.json')
    json_results = os.path.join(dir_job, 'factory.json')
    try:
        with open(json_info, 'r') as compatibility_file:
            info = json.load(compatibility_file)
        with open(json_results, 'r') as factory_file:
            results = json.load(factory_file)
    except OSError:
        abort(404)
    return render_template('home/job.html', manu=manu, hardware=hardware,
                           task_id=task_id, job=job_name,
                           info=info, results=results)


@home.route('/home/review/<int:hardware_id>/<string:task_id>')
@login_required
def task_review(hardware_id=None, task_id=None):
    """用例评审"""
    page = request.args.get('page', 1, type=int)  # 获取page参数值
    menu_id = Hardware.query.filter_by(id=hardware_id).first().manu_id

    query_time = db.session.query(TestReview.testcase_name,
                                  func.max(TestReview.create_time).label(
                                      "create_time")).filter_by(
        menu_id=menu_id).filter_by(
        hardware_id=hardware_id).filter_by(
        taskid=task_id).group_by(TestReview.testcase_name).all()

    return_data = []

    for i in query_time:
        review_data = db.session.query(
            TestReview).filter_by(hardware_id=hardware_id,
                                  taskid=task_id,
                                  testcase_name=i.testcase_name,
                                  create_time=i.create_time).all()
        return_data.append(review_data)

    per_page = 10
    page = request.args.get(get_page_parameter(), type=int, default=1)
    start = int((page - 1) * per_page)
    end = int(start + per_page)
    total = len(return_data)
    pagination = Pagination(bs_version=3, page=page, per_page=per_page,
                            total=total, search=False, record_name='data')
    if total >= 10:
        return_data = return_data[start, end]

    if total % per_page != 0:
        pages = int(total / per_page) + 1
    else:
        pages = int(total / per_page)

    return_datas = []
    for i in return_data:
        for item in i:
            return_datas.append(item)

    return render_template('home/review_new.html', hardware_id=hardware_id,
                           task_id=task_id, pagination=pagination,
                           pages=pages, return_datas=return_datas)


@home.route("/register/", methods=['GET', 'POST'])
def register():
    """
    注册功能
    """
    if "user_id" in session:
        return redirect(url_for("home.index"))
    form = RegistUser()
    if form.validate_on_submit():  # 提交注册表单
        data = form.data  # 接收表单数据
        manu = Manufacturer.query.filter_by(uuid=data['email']).first()
        if manu and manu.uuid == data['email']\
                and manu.manufacturer_name == data['manufacturer']:
            # 为User类属性赋值
            user = User(
                username=data['username'],
                email=data['email'],
                manufacturer=data['manufacturer'],
                password=generate_password_hash(data['password']),
            )
            db.session.add(user)
            db.session.commit()
            flash("注册成功", 'ok')
            return redirect(url_for('home.login'))
        flash("厂商名称或者邮箱输入不正确,请重新输入！", 'err')
    return render_template("/home/register.html", form=form)


@home.route('/login/', methods=['GET', 'POST'])
def login():
    """用户登录"""
    if "user_id" in session:        # 如果已经登录，则直接跳转到首页
        return redirect(url_for("home.get_hardware"))
    form = LoginForm()  # 实例化LoginForm类
    if form.validate_on_submit():  # 如果提交
        data = form.data  # 接收表单数据
        # 判断验证码
        if session.get('image').lower() != form.verify_code.data.lower():
            flash('验证码错误', "err")
            return render_template("/home/login.html", form=form)  # 返回登录页
        # 判断用户名是否存在
        user = User.query.filter_by(
            username=data["username"]).first()  # 获取用户信息
        if not user:
            flash("用户名不存在！", "err")  # 输出错误信息
            return render_template("/home/login.html", form=form)  # 返回登录页
        # 判断用户名和密码是否匹配
        if not user.check_password(
                data["password"]):  # 调用check_password()方法，检测用户名密码是否匹配
            flash("密码错误！", "err")  # 输出错误信息
            return render_template("/home/login.html", form=form)  # 返回登录页

        session["user_id"] = user.id  # 将user_id写入session, 后面用户判断用户是否登录
        session["user"] = user.username  # 将user_id写入session, 后面用户判断用户是否登录
        manu = User.query.filter_by(
            username=user.username).first().manufacturer
        manu_id = Manufacturer.query.filter_by(
            manufacturer_name=manu).first().id
        session["manu_id"] = manu_id
        return redirect(url_for("home.get_hardware"))  # 登录成功，跳转到首页
    return render_template("/home/login.html", form=form)  # 渲染登录页面模板


@home.route("/logout/")
def logout():
    """用户登出"""
    session.pop('user', None)
    session.pop('user_id', None)
    session.pop('manu_id', None)
    return redirect(url_for('home.login'))


@home.route("/modify_pwd/", methods=["GET", "POST"])
def modify_pwd():
    """修改用户密码"""
    form = PasswordForm()
    if form.validate_on_submit():
        data = form.data
        user = User.query.filter_by(username=session["user"]).first()
        user.password = generate_password_hash(data["password"])
        db.session.add(user)
        db.session.commit()
        return "<script>alert('密码修改成功');location.href='/';</script>"
    return render_template("home/modify_password.html", form=form)


@home.route('/hardware/review/<string:manu_id>/<string:hardware_id>/'
            '<string:task_id>/<string:job_id>')
@login_required
def get_job_review_detail(manu_id=None, hardware_id=None,
                          task_id=None, job_id=None):
    """
    获取日志信息
    """
    manu_name = Manufacturer.query.get(manu_id).manufacturer_name
    hardware_name = Hardware.query.get(hardware_id).hardware
    job_name = TestLog.query.get(job_id).job_name

    return get_job_detail(manu_name, hardware_name, task_id, job_name)
